

use super::common;
use super::common::Json;
use super::common::console;
use super::common::ToF64;
use super::math;
use super::animation;


#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct Character
{
    name: String,
    skill: [Option<Skill>; 3],
}

impl common::Json for Character {}
impl common::FromInput for Character {
    fn from_input() -> Self {
        println!();
        console::print_and_flush("CharacterName: ");
        let name = console::read();
        let mut skill:[Option<Skill>; 3] = [
            Option::None,
            Option::None,
            Option::None
        ];
        for index in 0..=2 {
            println!();
            skill[index] = Option::Some(Skill::from_input());
        }
        Self {
            name,
            skill
        }
    }
}
impl Character
{
    /**
     * 很快啊，skill就没了
    */
    pub fn new(name: &str, skill: [Option<Skill>; 3]) -> Self
    {
        Self {
            name: name.to_string(),
            skill
        }
    }

    pub fn get_skill(&self, index: usize) -> &Option<Skill>
    {
        &self.skill[index]
    }
    pub fn get_skills(&self) -> &[Option<Skill>; 3]
    {
        &self.skill
    }
}
/* 实现 Name特性 以实现 MultiJson特性 */
impl common::Name for Character
{
    fn name(&self) -> &String { &self.name }
    fn get_name(&self) -> &String { &self.name }
}
pub type CharacterMap = ::std::collections::HashMap<String, Character>;


#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub enum SkillType
{
    None,
    Normal,
    Final
}
trait ToSkillType {
    fn to_skill_type(&self) -> SkillType;
}
impl ToSkillType for String {
    fn to_skill_type(&self) -> SkillType {
        match ::core::str::FromStr::from_str(self) {
            Ok(r) => r,
            Err(e) => {
                eprintln!("{}", e);
                SkillType::None
            }
        }
    }
}
impl ToSkillType for str {
    fn to_skill_type(&self) -> SkillType {
        match ::core::str::FromStr::from_str(self) {
            Ok(r) => r,
            Err(e) => {
                eprintln!("{}", e);
                SkillType::None
            }
        }
    }
}
impl ::std::string::ToString for SkillType {
    fn to_string(&self) -> String {
        match self {
            SkillType::None => "None".to_string(),
            SkillType::Normal => "Normal".to_string(),
            SkillType::Final => "Final".to_string()
        }
    }
}
impl ::core::str::FromStr for SkillType {
    type Err = ::core::convert::Infallible;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "None" => Ok(SkillType::None),
            "Normal" => Ok(SkillType::Normal),
            "Final" => Ok(SkillType::Final),
            _ => Ok(SkillType::None)
        }
    }
}



#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct Skill
{
    name: String,
    synopsis: String,
    atk: f64,
    r#type: SkillType
}
impl common::FromInput for Skill {
    fn from_input() -> Self {
        println!();
        console::print_and_flush("SkillName: ");
        let name = console::read();

        console::print_and_flush("SkillSynopsis: ");
        let synopsis = console::read();

        console::print_and_flush("SkillATK: ");
        let atk = console::read();

        console::println("SkillType (input number or full name please)");
        console::println("\t1.None");
        console::println("\t2.Normal");
        console::println("\t3.Final");
        console::print(": ");
        console::flush();
        let mut r#type = console::read();
        match r#type.as_str().trim() {
            "1" => r#type = "None".to_string(),
            "2" => r#type = "Normal".to_string(),
            "3" => r#type = "Final".to_string(),
            "None" => {},
            "Normal" => {},
            "Final" => {},
            _ => {}
        }

        Self {
            name,
            synopsis,
            atk: atk.to_f64(),
            r#type: r#type.to_skill_type()
        }
    }
}
impl Skill
{
    pub fn new(name: &str, synopsis: &str, atk: f64, r#type: SkillType) -> Self
    {
        Self {
            name: name.to_string(),
            synopsis: synopsis.to_string(),
            atk,
            r#type
        }
    }
}





#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub enum GameCharacterState
{
    Stand,      // 站立
    Fly,        // 飞
    Attack,     // 普攻
    HurtStand,  // 受伤状态-站立
    HurtFall,   // 受伤状态-击倒
    SkillNormal,// 技能体，唯技能可打断
    SkillFinal, // 奥义状态
}



#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct GameCharacterJsonDataObject
{
    name: String,
    skill: [Option<Skill>; 3],
    pub hp: f64,
    pub speed: f64,
}
impl common::Name for GameCharacterJsonDataObject
{
    fn name(&self) -> &String { &self.name }
    fn get_name(&self) -> &String { &self.name }
}
impl common::Json for GameCharacterJsonDataObject{}


#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct GameCharacter
{
    name: String,
    skill: [Option<Skill>; 3],
    pub hp: f64,
    skill_points: u8,   // 0-4
    pub state: GameCharacterState,
    pub speed: f64,
    bounds: math::Rectangle,
    animation_manager: animation::AnimationManager
}
impl common::Name for GameCharacter {
    fn name(&self) -> &String { &self.name }
    fn get_name(&self) -> &String { &self.name }
}
impl common::Json for GameCharacter {
    fn from_json(path: &str) -> Option<Self>
    {
        let option = GameCharacterJsonDataObject::from_json(path);
        if option.is_none() { return Option::None }
        let gc_json = option.unwrap();
        Option::Some(Self::from_game_character_json_data_object(gc_json, Default::default()))
    }
    fn write_json(&self, path: &str){ self.as_game_character_json_data_object().write_json(path); }
}
impl GameCharacter
{
    /**
     * 很快啊，bounds就没了
    */
    pub fn new(name: &str, skill: [Option<Skill>; 3], hp: f64, speed: f64, bounds: math::Rectangle) -> Self
    {
        Self {
            name: name.to_string(),
            skill,
            hp,
            skill_points: 2,
            state: GameCharacterState::Stand,
            speed,
            bounds,
            animation_manager: animation::AnimationManager::new()
        }
    }


    pub fn from_character(c: Character, hp: f64, speed: f64, bounds: math::Rectangle) -> Self
    {
        Self {
            name: c.name,
            skill: c.skill,
            hp,
            skill_points: 2,
            state: GameCharacterState::Stand,
            speed,
            bounds,
            animation_manager: animation::AnimationManager::new()
        }
    }
    pub fn as_character(&self) -> Character{Character { name: self.name.to_string(), skill: self.skill.clone() }}
    pub fn from_game_character_json_data_object(c: GameCharacterJsonDataObject, bounds: math::Rectangle) -> Self
    {
        GameCharacter {
            name: c.name,
            skill: c.skill,
            hp: c.hp,
            skill_points: 2,
            state: GameCharacterState::Stand,
            speed: c.speed,
            bounds,
            animation_manager: animation::AnimationManager::new()
        }
    }
    pub fn as_game_character_json_data_object(&self) -> GameCharacterJsonDataObject
    {
        GameCharacterJsonDataObject {
            name: self.name.to_string(),
            skill: self.skill.clone(),
            hp: self.hp,
            speed: self.speed
        }
    }



    pub fn get_x(&self) -> f64 { self.bounds.left }
    pub fn get_y(&self) -> f64 { self.bounds.top }
    pub fn get_width(&self) -> f64 { self.bounds.right - self.bounds.left }
    pub fn get_height(&self) -> f64 { self.bounds.bottom - self.bounds.top }

    pub fn get_skill_points(&self) -> u8 { self.skill_points }
    pub fn get_animation_manager(&self) -> &animation::AnimationManager
    {
        &self.animation_manager
    }


    /**
     * 这个一般不用
    */
    pub fn set_hp(&mut self, hp: f64) -> &mut Self
    {
        self.hp = hp;
        self
    }

    pub fn set_skill_points(&mut self, points: u8) -> &mut Self
    {
        if self.skill_points > 4 {
            self.skill_points = 4;
            return self;
        }
        self.skill_points = points;
        self
    }

    /**
     * 
    */
    pub fn set_bounds(&mut self, bounds: &math::Rectangle) -> &mut Self
    {
        self.bounds.left = bounds.left;
        self.bounds.right = bounds.right;
        self.bounds.top = bounds.top;
        self.bounds.bottom = bounds.bottom;
        self
    }


    pub fn set_xy(&mut self, x: f64, y: f64) -> &mut Self
    {
        self.bounds.right += x - self.bounds.left;// right - left = width; x + width;
        self.bounds.left = x;
        self.bounds.bottom += y - self.bounds.top;// bottom - top = height; y + height;
        self.bounds.top = y;
        self
    }

    pub fn set_x(&mut self, x: f64) -> &mut Self
    {
        self.bounds.right += x - self.bounds.left;// right - left = width; x + width;
        self.bounds.left = x;
        self
    }
    pub fn set_y(&mut self, y: f64) -> &mut Self
    {
        self.bounds.bottom += y - self.bounds.top;// bottom - top = height; y + height;
        self.bounds.top = y;
        self
    }
    pub fn set_width(&mut self, width: f64) -> &mut Self
    {
        self.bounds.right = self.bounds.left + width;
        self
    }
    pub fn set_height(&mut self, height: f64) -> &mut Self
    {
        self.bounds.bottom = self.bounds.top + height;
        self
    }


    /**
     * 很快啊，state就没了
     * 这个一般不用
    */
    pub fn set_state(&mut self, state: GameCharacterState) -> &mut Self
    {
        self.state = state;
        self
    }


    pub fn set_animation_manager(&mut self, manager: animation::AnimationManager) -> &mut Self
    {
        self.animation_manager = manager;
        self
    }

    pub fn insert_animation(&mut self, animation: animation::AnimationData) -> &mut Self
    {
        self.animation_manager.insert_animation(animation);
        self
    }
    pub fn remove_animation(&mut self, name: &str) -> &mut Self
    {
        self.animation_manager.remove_animation(name);
        self
    }

    pub fn play_animation(&mut self, name: &str)
    {
        self.animation_manager.play(name);
    }
    pub fn stop_animation(&mut self) { self.animation_manager.stop_play() }


    pub fn update(&mut self)
    {
        let f_option = self.animation_manager.get_current_frame();
        if f_option.is_some()
        {
            let f = f_option.unwrap();
            self.bounds.right = self.bounds.left + f.get_width();
            self.bounds.top = self.bounds.bottom - f.get_height();
        }
    }
}




pub type GameCharacterManager = ::std::collections::HashMap<String, GameCharacter>;
trait GameCharacterManagerLabelTrait {}
impl GameCharacterManagerLabelTrait for GameCharacterManager {}
trait GameCharacterManagerTrait
    where Self: GameCharacterManagerLabelTrait
{
    fn load_game_character_json_data_object_json_file(&mut self, json_path: &str);
    fn load_multi_game_character_json_data_object_json_file(&mut self, dir_path: &str) -> Result<(), Box<dyn ::std::error::Error>>;
    fn update(&mut self);
    fn insert_game_character(&mut self, gc: GameCharacter);
    fn insert_animation(&mut self, character_name: &str, animation: animation::AnimationData);

    fn get_game_character(&self, character_name: &str) -> Option<&GameCharacter>;
    fn get_game_character_mut(&mut self, character_name: &str) -> Option<&mut GameCharacter>;
    fn get_animation_manager(&self, character_name: &str) -> Option<&animation::AnimationManager>;
    fn get_animation(&self, character_name: &str, animation_name: &str) -> Option<&animation::AnimationData>;

    
    /* 可以用animation::AnimationManager::from_multi_json */
    fn set_animation_manager(&mut self, character_name: &str, manager: animation::AnimationManager);
}
impl GameCharacterManagerTrait for GameCharacterManager
{
    fn load_game_character_json_data_object_json_file(&mut self, json_path: &str)
    {
        let option = GameCharacter::from_json(json_path);
        if option.is_none()
        {
            eprintln!("load_game_character_json() load error");
            return;
        }
        let gc = option.unwrap();
        self.insert(gc.name.to_string(), gc);
    }
    fn load_multi_game_character_json_data_object_json_file(&mut self, dir_path: &str) -> Result<(), Box<dyn ::std::error::Error>>
    {
        let read_dir = ::std::fs::read_dir(dir_path)?;
        for result in read_dir
        {
            if result.is_err() {
                eprintln!("{}", result.unwrap_err());
                continue;//读取下一个条目
            }
            let entry = result.unwrap();
            let path = entry.path();
            let path_str = path.to_str().unwrap();
            if entry.file_type().unwrap().is_dir() {
                eprintln!("{}不是文件", path_str);
                continue;//读取下一个条目
            }
            self.load_game_character_json_data_object_json_file(path_str);
        }
        Ok(())
    }


    fn update(&mut self)
    {
        for (_name, gc) in self { gc.update(); }
    }

    fn insert_game_character(&mut self, gc: GameCharacter) { self.insert(gc.name.to_string(), gc); }
    fn insert_animation(&mut self, character_name: &str, animation: animation::AnimationData)
    {
        let gc_option = self.get_mut(character_name);
        if gc_option.is_none() {
            eprintln!("角色不存在");
            return;
        }
        let gc = gc_option.unwrap();
        gc.insert_animation(animation);
    }

    fn get_game_character(&self, character_name: &str) -> Option<&GameCharacter> { self.get(character_name) }
    fn get_game_character_mut(&mut self, character_name: &str) -> Option<&mut GameCharacter> { self.get_mut(character_name) }
    fn get_animation_manager(&self, character_name: &str) -> Option<&animation::AnimationManager>
    {
        let gc_option = self.get(character_name);
        if gc_option.is_none() {
            eprintln!("角色不存在");
            return Option::None;
        }
        Option::Some(gc_option.unwrap().get_animation_manager())
    }
    fn get_animation(&self, character_name: &str, animation_name: &str) -> Option<&animation::AnimationData>
    {
        let gc_option = self.get(character_name);
        if gc_option.is_none() {
            eprintln!("角色不存在");
            return Option::None;
        }
        let gc = gc_option.unwrap();
        gc.get_animation_manager().get_animation(animation_name)
    }

    
    /* 可以用animation::AnimationManager::from_multi_json */
    fn set_animation_manager(&mut self, character_name: &str, manager: animation::AnimationManager)
    {
        let gc_option = self.get_mut(character_name);
        if gc_option.is_none() {
            eprintln!("角色不存在");
            return;
        }
        let gc = gc_option.unwrap();
        gc.set_animation_manager(manager);
    }

}






#[cfg(test)]
mod tests {
    use super::common::Json;
    use super::*;

    #[test]
    fn character_write_json_skill_none()
    {
        let c = Character::new(
            "Naruto",
            [
                Option::None,
                Option::None,
                Option::None
            ]
        );
        c.write_json("character_skill_none.json");
    }


    #[test]
    fn game_character_manager_init()
    {
        let mut manager = GameCharacterManager::new();
        manager.load_multi_game_character_json_data_object_json_file("./character")
            .expect("read dir error");
        println!("{:#?}", manager);
    }
}


